/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { KEYBOARD_KEY } from '@app-cad/common/Constants';
import { wsApi } from '@app-cad/server';
import { Vector3 } from 'three-legacy';

import {
  CENTEREVENTS,
  CadScene,
  EventsRes,
  SceneGraph,
  ThickLine,
} from '@amcax/base';
import { eventCenterManager } from '@app-base/common/events/EventCenterManager';
import { ctx2 } from '@app-cad/module';

type MouseBoxState = 'none' | 'draw' | 'extrude';

const cmdMouseBoxInit = async (cmdContext) => {
  const cadScene = ctx2.cadScene as CadScene;
  const sceneSetup = ctx2.viewer.sceneSetup;
  const assisGroup = cadScene.assisGroup;
  // 固定为 XOY 平面
  const planeNormal: Vector3 = new Vector3(0, 0, 1);
  const planeOrigin: Vector3 = new Vector3(0, 0, 0);

  const lineWidth = 1; // 绘制的线宽
  const lineColor = 0x1890f5; // 线条颜色
  let stepStatus: MouseBoxState = 'none';

  let startPoint: Vector3; // 矩形起点
  let endPoint: Vector3; // 矩形终点
  let height = 0;

  // 注册鼠标键盘
  eventCenterManager.activeEventCenter
    .setState('mouse-box')
    .on(CENTEREVENTS.KEYUP, keyupEvent)
    .on(CENTEREVENTS.POINTERUP, onMouseClick)
    .on(CENTEREVENTS.POINTERMOVE, onMouseMove);

  // 命令完成或者取消，释放资源
  async function exitCmdMouseBox() {
    stepStatus = 'none';

    if (cmdContext) {
      cmdContext.store.highlightCmdId = '';
    }
    eventCenterManager.activeEventCenter
      .off(CENTEREVENTS.POINTERMOVE, onMouseMove)
      .off(CENTEREVENTS.POINTERUP, onMouseClick)
      .off(CENTEREVENTS.KEYUP, keyupEvent)
      .setDefault();

    assisGroup.clear();
    SceneGraph.emptyGroup(assisGroup);
    ctx2.viewer.requestRender();
  }

  // 命令完成，调用API
  async function drawDoneCallback() {
    const pos = [startPoint.x, startPoint.y, 0];
    if (endPoint.x < startPoint.x) {
      pos[0] = endPoint.x;
    }
    if (endPoint.y < startPoint.y) {
      pos[1] = endPoint.y;
    }
    await wsApi.createPrimitive(
      'Box',
      {
        length: Math.abs(startPoint.x - endPoint.x),
        width: Math.abs(startPoint.y - endPoint.y),
        height: height,
      },
      [pos, [0, 0, 1], [1, 0, 0]],
    );
  }

  // 键盘事件：取消
  function keyupEvent(e) {
    if (e.key == KEYBOARD_KEY.ESC) {
      exitCmdMouseBox();
    }
  }

  // 鼠标点击，绘制步骤确定并进入下一个步骤
  function onMouseClick() {
    if (stepStatus == 'none') {
      stepStatus = 'draw';
      return;
    }
    if (stepStatus == 'draw') {
      stepStatus = 'extrude';
      return;
    }
    if (stepStatus == 'extrude') {
      drawDoneCallback();
      exitCmdMouseBox();
    }
  }

  // 鼠标移动，记录鼠标点并计算需要的值
  function onMouseMove(e: EventsRes) {
    if (stepStatus == 'none') {
      startPoint = sceneSetup.mouseOnPlane(
        e.mouse.x,
        e.mouse.y,
        planeNormal,
        planeOrigin,
      );
    }
    if (stepStatus == 'draw') {
      endPoint = sceneSetup.mouseOnPlane(
        e.mouse.x,
        e.mouse.y,
        planeNormal,
        planeOrigin,
      );
      showPreview();
    }
    if (stepStatus == 'extrude') {
      const camNormal = sceneSetup.getCameraNormal().clone().normalize();
      const extrudePoint = sceneSetup.screenToWorld(
        e.mouse.x,
        e.mouse.y,
        camNormal.clone(),
        endPoint,
      );
      height = extrudePoint.z;
      if (height != 0) {
        showPreview();
      }
    }
  }

  function showPreview() {
    let tess;
    // draw rect
    if (stepStatus == 'draw') {
      tess = [
        [startPoint.x, startPoint.y, 0],
        [startPoint.x, endPoint.y, 0],
        [endPoint.x, endPoint.y, 0],
        [endPoint.x, startPoint.y, 0],
        [startPoint.x, startPoint.y, 0],
      ];
    }
    // draw box wireframe，不好意思，画了些重合的线条
    if (stepStatus == 'extrude') {
      tess = [
        [startPoint.x, startPoint.y, 0],
        [startPoint.x, endPoint.y, 0],
        [endPoint.x, endPoint.y, 0],
        [endPoint.x, startPoint.y, 0],
        [startPoint.x, startPoint.y, 0],

        [startPoint.x, startPoint.y, height],
        [startPoint.x, endPoint.y, height],
        [endPoint.x, endPoint.y, height],
        [endPoint.x, startPoint.y, height],
        [startPoint.x, startPoint.y, height],

        [endPoint.x, startPoint.y, height],
        [endPoint.x, startPoint.y, 0],
        [endPoint.x, endPoint.y, 0],
        [endPoint.x, endPoint.y, height],
        [startPoint.x, endPoint.y, height],
        [startPoint.x, endPoint.y, 0],
      ];
    }
    assisGroup.clear();
    const objs = new ThickLine(tess, lineWidth, lineColor, false, true);
    assisGroup.add(objs);
    ctx2.viewer.requestRender();
  }
};

export const cmdMouseBox = {
  id: 'CmdMouseBox',
  label: 'command.box',
  icon: 'CmdBlock',
  invoke: cmdMouseBoxInit,
};
